﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace M3G {
    public class Texture2D : Texture {

        #region Constant
        // Function
        public const int FuncAdd      = 224;
        public const int FuncBlend    = 225;
        public const int FuncDecal    = 226;
        public const int FuncModulate = 227;
        public const int FuncReplace  = 228;
        // Wrap mode
        public const int WrapClamp    = 240;
        public const int WrapRepeat   = 241;
        public const int WrapMirror   = 242;
        #endregion

        #region Field
        int             wrappingS;
        int             wrappingT;
        int             blendFunction;
        uint            blendColor;
        TextureCombiner textureCombiner;
        #endregion

        #region Method

        public Texture2D (Image2D image)
            : base (image) {
            this.wrappingS = WrapRepeat;
            this.wrappingT = WrapRepeat;
            this.blendFunction = FuncModulate;
            this.blendColor = 0x00000000u;
            this.textureCombiner = null;
        }

        public Texture2D (DynamicImage2D image)
            : base (image) {
            this.wrappingS = WrapRepeat;
            this.wrappingT = WrapRepeat;
            this.blendFunction = FuncModulate;
            this.blendColor = 0x00000000u;
            this.textureCombiner = null;

        }

        protected Texture2D (Texture2D texture)
            : base (texture) {
            this.wrappingS = texture.wrappingS;
            this.wrappingT = texture.wrappingT;
            this.blendFunction = texture.blendFunction;
            this.blendColor = texture.blendColor;
            this.textureCombiner = texture.textureCombiner;
        }


        public uint BlendColor {
            get { return blendColor; }
            set {
                this.blendColor = value;
            }
        }

        public int Blending {
            get { return blendFunction; }
            set {
                var func = value;
                if (func < FuncAdd || func > FuncReplace) {
                    throw new ArgumentException ("Blending func must be FuncReplace,FuncModulate,FuncDecal,FuncBlend,FuncAdd, func=" + func);
                }

                this.blendFunction = func;
            }
        }

        public TextureCombiner Combiner {
            get { return textureCombiner; }
        }

        public void SetCombiner (TextureCombiner textureCombiner) {

            this.textureCombiner = textureCombiner;
        }



        public Image2D Image {
            get {
                return ImageBase as Image2D;
            }
        }

        public void SetImage (Image2D image) {
            if (image == null) {
                throw new ArgumentException ("Image is null");
            }

            base.SetImageBase (image);
        }

        public DynamicImage2D DynamicImage {
            get {
                return ImageBase as DynamicImage2D;
            }
        }

        public void SetDynamicImage (DynamicImage2D image) {
            if (image == null) {
                throw new ArgumentNullException ("Image is null");
            }

            base.SetImageBase (image);
        }



        public int WrappingS {
            get { return wrappingS; }
        }

        public int WrappingT {
            get { return wrappingT; }
        }

        public void SetWrapping (int wrapS, int wrapT) {
            if (wrapS < WrapClamp || wrapS > WrapMirror || wrapT < WrapClamp || wrapT > WrapMirror) {
                throw new ArgumentException ("Wraping mode must be WrapClamp, WrapRpeat, WrapMirror, s=" + wrapS + ",t=" + wrapT);
            }

            this.wrappingS = wrapS;
            this.wrappingT = wrapT;
        }

        public override Object3D[] References {
            get {
                var q = new List<Object3D> ();
                q.AddRange (base.References);
                q.Add (textureCombiner);
                q.RemoveAll (x => x == null);
                return q.ToArray ();
            }
        }

        public override int Animate (int time) {

            base.Animate (time);

            var animatedColor        = new float[3];
            var value                = new float[3];
            var animated             = new Dictionary<int, bool> (1);

            for (var i=0; i < AnimationTrackCount; i++) {
                var track = AnimationTrack[i];
                var ch    = AnimationTrackChannel[i];
                if (track.Controller == null || !track.Controller.Active (time)) {
                    continue;
                }
                var property = track.TargetProperty;
                var weight   = track.Controller.Weight;

                animated[property] = true;
                switch (property) {
                    case M3G.AnimationTrack.Color: {
                        track.Sample (time, ch, value);
                        animatedColor[0] = value[0] * weight;
                        animatedColor[1] = value[1] * weight;
                        animatedColor[2] = value[2] * weight;
                        break;
                    }
                }// switch
            }  // for

            if (animated[M3G.AnimationTrack.Color]) {
                var r = (uint)animatedColor[0].Clamp (0, 1) * 255;
                var g = (uint)animatedColor[1].Clamp (0, 1) * 255;
                var b = (uint)animatedColor[2].Clamp (0, 1) * 255;
                this.blendColor = (r << 16) | (g << 8) | (b << 0);
            }

            return 0;
        }

        public override Object3D Duplicate () {
            return new Texture2D (this);
        }
        #endregion

    }
}
